﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RestSharp.Portable;
using System.Net.Http;
using System.Threading.Tasks;
using System.Net;
using RestSharp.Portable.Authenticators;
using Newtonsoft.Json;
using System.Net.Http.Headers;

namespace Trakt
{
    public sealed class TraktClient
    {
        public const string ApiBaseUrl = "http://api.v2.trakt.tv"; // TODO: Change to "https" when available
        public const string LocalOAuthRedirectUrl = "urn:ietf:wg:oauth:2.0:oob";
        public const string ContentType = "application/json";

        public static readonly Dictionary<HttpStatusCode, string> StatusMessages = new Dictionary<HttpStatusCode, string>()
        {
            { HttpStatusCode.OK, "Success" },
            { HttpStatusCode.Created, "Success - new resource created (POST)" },
            { HttpStatusCode.NoContent, "Success - no content to return (DELETE)" },
            { HttpStatusCode.BadRequest, "Bad Request - request couldn't be parsed" },
            { HttpStatusCode.Unauthorized, "Unauthorized - OAuth must be provided" },
            { HttpStatusCode.Forbidden, "Forbidden - invalid API key" },
            { HttpStatusCode.NotFound, "Not Found - method exists, but no record found" },
            { HttpStatusCode.MethodNotAllowed, "Method Not Found - method doesn't exist" },
            { HttpStatusCode.Conflict, "Conflict - resource already created" },
            { (HttpStatusCode)422, "Unprocessable Entity - validation errors" },
            { (HttpStatusCode)429, "Rate Limit Exceeded" },
            { HttpStatusCode.InternalServerError, "Server Error" },
            { HttpStatusCode.ServiceUnavailable, "Service Unavailable - server overloaded" }
        };

        public ITraktClientConfiguration Configuration { get; private set; }
        public JsonSerializer Serializer { get; private set; }

        public string UserKey { get; set; }

        private RestClient _Client;

        public TraktClient(ITraktClientConfiguration configuration)
        {
            Configuration = configuration;
            Serializer = new JsonSerializer();
            Serializer.Converters.Add(new TraktResponseConverter());

            _Client = new RestClient(ApiBaseUrl);
            _Client.Authenticator = new TraktAuthenticator(configuration, Serializer) as IAuthenticator;

            _Client.DefaultParameters.Add(new Parameter()
                {
                    Type = ParameterType.HttpHeader,
                    ValidateOnAdd = false,
                    Name = "trakt-api-version",
                    Value = "2"
                });
            _Client.DefaultParameters.Add(new Parameter()
                {
                    Type = ParameterType.HttpHeader,
                    ValidateOnAdd = false,
                    Name = "trakt-api-key",
                    Value = Configuration.ClientId
                });

            // message.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
        }

        #region Search
        public async Task<IRestResponse> Search(string query, ElementType type = null)
        {
            // Construct request
            const string resource = "search";
            var request = new RestRequest(resource, HttpMethod.Get);

            // Add parameters
            request.AddQueryParameter("query", Uri.EscapeDataString(query));
            if (type != null) request.AddQueryParameter("type", type);

            // Call
            return await _Client.Execute(request).ConfigureAwait(false);
        }

        public HttpWebResponse SearchBadly(string query)
        {
            var request = HttpWebRequest.CreateHttp(ApiBaseUrl + "/search?query=" + query);
            request.Method = "GET";
            request.ContentType = "application/json";
            request.Headers["trakt-api-key"] = Configuration.ClientId;
            request.Headers["trakt-api-version"] = "2";

            var task = request.GetResponseAsync();
            task.Wait();
            return task.Result as HttpWebResponse;
        }
        #endregion
    }
}
